﻿/*
 * Programming Graphical User Interfaces
 * Example program: Diagram
 * Diagram.cs: Implements the data model on the application.
 * Jarkko Leponiemi 2004
 */

using System;
using System.Collections;
using System.Drawing;


namespace SharppiFlowEditor.models
{
    /*
    * The delegate for diagram change events.
    */
    public delegate void DiagramEventHandler(object sender, FlowChartEventArgs e);

    /*
     * The model class for diagrams.
     */
    public class AppModel
    {

        public ArrayList nodes;
        private ArrayList connectors;

        /*
         * Create the model.
         */
        public AppModel()
        {
            nodes = new ArrayList();
            connectors = new ArrayList();
        }

        private void NewDocument()
        {
            // testzzzz
        }

        // Exit application
        public void ExitApplication()
        {
            //Application.Exit();
        }

        /*
         * Get the nodes of the diagram.
         */
        public IList Nodes
        {
            get { return nodes; }
        }

        /*
         * Get the connectors of the diagram.
         */
        public IList Connectors
        {
            get { return connectors; }
        }

        /*
         * Create a new node and the corresponding change event.
         *  title = the title of the new node
         *  x and y = the coordinates of the center point of the new node
         */
        /*public Node CreateNode(string title, float x, float y)
        {
            AbstractNode n = new Node(title, x, y);
            nodes.Add(n);
            // raise a change event
            OnDiagramChange(new DiagramEventArgs(n, true));
            return n;
        }*/

        public AbstractNode createAbstractNodeRENAMETHISMETHODLATER(int x, int y, int width, int height, string title, int type)
        {
            AbstractNode an;
            switch (type)
	        {
                case 1:
                    an = new EndNode(x, y, width, height);
                    an.Title = title;
                    an.BGColor = Color.HotPink;
                    an.Type = type;
                    nodes.Add(an);
                    OnDiagramChange(new FlowChartEventArgs(an, true));
                    return an;
                case 2:
                    an = new ActionNode(x, y, width, height);
                    an.Title = title;
                    an.BGColor = Color.Azure;
                    an.Type = type;
                    nodes.Add(an);
                    OnDiagramChange(new FlowChartEventArgs(an, true));
                    return an;               
		        case 3: 
                    an = new ConditionalNode(x, y, width, height);
                    an.Title = title;
                    an.Type = type;
                    an.BGColor = Color.LightGreen;
                    nodes.Add(an);
                    OnDiagramChange(new FlowChartEventArgs(an, true));
                    return an; 
	        }
           
            return null;
        }

        /*
         * Create a new connector and the change event.
         *  n1 and n2 = the connected nodes
         */
        public Connector CreateConnector(AbstractNode n1, AbstractNode n2, string text)
        {

            Connector c;
            if (text.Length == 0)
                c = new Connector(n1, n2);
            else
                c = new Connector(n1, n2, text);
            connectors.Add(c);
            // raise the change event
            OnDiagramChange(new FlowChartEventArgs(c, true));
            return c;
        }

        /*
         * Get the connectors attached to the specified node.
         */
        public Connector[] GetNodeConnectors(AbstractNode n)
        {
            ArrayList conns = new ArrayList();
            IEnumerator e = connectors.GetEnumerator();
            while (e.MoveNext())
            {
                Connector c = (Connector)e.Current;
                if (c.Node1 == n || c.Node2 == n)
                {
                    conns.Add(c);
                }
            }
            return (Connector[])conns.ToArray(Type.GetType("SharppiFlowEditor.models.Connector"));
        }


        /*
         * Move a node and create the necessary change events.
         *  n = the moving node
         *  x and y = the new center point
         */
        public void MoveNode(AbstractNode n, float x, float y)
        {
            if (n.getBoundingRect().X != x || n.getBoundingRect().Y != y)
            {
                Connector[] conns = GetNodeConnectors(n);
                // raise a change event for each connector in original state
                IEnumerator e = connectors.GetEnumerator();
                while (e.MoveNext())
                {
                    Connector c = (Connector)e.Current;
                    OnDiagramChange(new FlowChartEventArgs(c, false));
                }
                // raise a change event for the node in the old location
                OnDiagramChange(new FlowChartEventArgs(n, false));

                n.setBoundingRectLocation((int)x, (int)y);
                
                // raise a change event for each connector in new state
                e.Reset();
                while (e.MoveNext())
                {
                    Connector c = (Connector)e.Current;
                    OnDiagramChange(new FlowChartEventArgs(c, false));
                }
                // raise a change event for the node in new location
                // last is true
                OnDiagramChange(new FlowChartEventArgs(n, true));
            }
        }

        /*
         * Are the specified node already connected?
         */
        public bool Connected(AbstractNode n1, AbstractNode n2)
        {
            IEnumerator e = connectors.GetEnumerator();
            while (e.MoveNext())
            {
                Connector c = (Connector)e.Current;
                if ((c.Node1 == n1 && c.Node2 == n2) || (c.Node1 == n2 && c.Node2 == n1))
                {
                    return true;
                }
            }
            return false;
        }

        /*
         * The event for diagram change events.
         */
        public event DiagramEventHandler DiagramChange;

        /*
         * Notify the event delegates about an event.
         */
        protected virtual void OnDiagramChange(FlowChartEventArgs e)
        {
            if (DiagramChange != null)
            {
                // invoke the delegates
                DiagramChange(this, e);
            }
        }

        internal void DeleteNode(AbstractNode n)
        {
            for (int i = 0; i < nodes.Count; i++)
            {
                Connector[] conns = GetNodeConnectors(n);
                if (conns.Length > 0)
                {
                    for (int j = 0; j < connectors.Count; j++)
                    {
                        Connector c = (Connector)connectors[j];
                        if (c.Node1.Equals(n) || c.Node2.Equals(n))
                            connectors.RemoveAt(j);
                    }
                }
                if (nodes[i].Equals(n))
                    nodes.RemoveAt(i);
            }
        }
    }
}